package plugin.validator;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.regex.Matcher;
import java.util.regex.Pattern;


import org.pentaho.di.core.Const;

public class Validator {

	static DateFormat formater = new SimpleDateFormat("yyyy-MM-dd");
	static Result result = new Result();

	public static Result verifyPesel(String pesel) {

		// field is empty
		if (Const.isEmpty(pesel)) {
			result.fill(false, "", "");
			return result;
		}

		// invalid length
		if (pesel.length() != 11) {
			result.fill(false, "", "");
			return result;
		}

		// field contains non-numbers
		Matcher m = Pattern.compile("[^\\d]").matcher(pesel);
		if (m.find()) {

		}

		int year = Integer.parseInt(pesel.substring(0, 2));
		int month = Integer.parseInt(pesel.substring(2, 4));
		int day = Integer.parseInt(pesel.substring(4, 6));

		// unvalid month value
		int mappedMonth = checkAndMapMonth(month);
		if (mappedMonth == -1) {
			result.fill(false, "", "");
			return result;
		}

		if (!checkIfDateIsValid(year, month, mappedMonth, day)) {
			result.fill(false, "", "");
			return result;
		}

		int sex = Character.digit(pesel.charAt(9), 10) % 2;
		result.setSex((sex == 0 ? "F" : "M"));

		int cc = Character.digit(pesel.charAt(10), 10);
		result.setCorrect(checkCC(cc, pesel.toCharArray()));
		return result;
	}

	
	
	
	
	
	/* see new and old PESEL numbers http://pl.wikipedia.org/wiki/PESEL */
	private static int checkAndMapMonth(int month) {
		int newMonth = month % 20;
		return (newMonth < 1 || newMonth > 12) ? -1 : newMonth;
	}

	
	
	private static boolean checkIfDateIsValid(int year, int month,
			int mappedMonth, int day) {
		int group = month / 20;
		switch (group) {
		case 0:
			year += 1900;
			break;
		case 1:
			year += 2000;
			break;
		case 2:
			year += 2100;
			break;
		case 3:
			year += 2200;
			break;
		case 4:
			year += 1800;
			break;
		}

		Calendar calendar = Calendar.getInstance();
		calendar.set(year, mappedMonth -1, day);
		if (calendar.get(Calendar.YEAR) != year
				|| calendar.get(Calendar.MONTH) != mappedMonth -1
				|| calendar.get(Calendar.DAY_OF_MONTH) != day)
			return false;

		// date is correct
		result.setBirthDate(formater.format(calendar.getTime()));
		return true;
	}

	// verify last digit - CC
	private static boolean checkCC(int cc, char[] pesel) {
		int result = 0;
		int factors[] = {1,3,7,9};
		for (int i = 0; i < pesel.length-1; i++) {
			int digit = Character.digit(pesel[i], 10);
			result += factors[i%factors.length]*digit;
		}
		result %= 10;
		return (10 - result == cc ? true : false);
	}
}
